home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / ui-local.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-04  |  16.7 KB  |  678 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. #ifndef lint
  12. static char *RCSid = "$Header: /usr/local/ls6/src+data/src/freeWAIS-sf/ir/RCS/ui-local.c,v 1.4 1994/08/05 07:12:49 pfeifer Exp $";
  13. #endif
  14.  
  15. /* Change log:
  16.  * $Log: ui-local.c,v $
  17.  * Revision 1.4  1994/08/05  07:12:49  pfeifer
  18.  * Release beta 04
  19.  *
  20.  * Revision 1.3  1994/05/20  12:57:50  pfeifer
  21.  * beta
  22.  *
  23.  * Revision 1.2  1994/03/08  21:07:05  pfeifer
  24.  * Patchlevel 04
  25.  *
  26.  * Revision 1.1  1993/02/16  15:05:35  freewais
  27.  * Initial revision
  28.  *
  29.  * Revision 1.16  92/03/18  09:01:09  jonathan
  30.  * don't free DocObjs[0]->Type, it's a copy of the input!
  31.  * 
  32.  * Revision 1.15  92/03/06  12:53:03  jonathan
  33.  * Plug another memory leak.  From ericb@baker.dartmouth.edu (Eric J Bivona).
  34.  * 
  35.  * Revision 1.14  92/02/14  15:26:53  jonathan
  36.  * Conditionalized interpret_message and locally_answer_message so client need
  37.  * not include search engine.
  38.  * 
  39.  * Revision 1.13  92/02/12  13:53:41  jonathan
  40.  * Added "$Log" so RCS will put the log message in the header
  41.  * 
  42.  * 
  43. */
  44.  
  45. /* 
  46.  * this is a simple ui toolkit for building other ui's on top.
  47.  * -brewster
  48.  * 
  49.  * top level functions:
  50.  *   generate_search_apdu
  51.  *   generate_retrieval_apdu
  52.  *   interpret_message
  53.  *
  54.  */
  55.  
  56. /* to do:
  57.  *   generate multiple queries for long documents.
  58.  *     this will crash if the file being retrieved is larger than 100k.
  59.  *   
  60.  */
  61.  
  62. #include "ui.h"
  63. #include "wutil.h"
  64. #include "ustubs.h"
  65. #include "futil.h"
  66.  
  67. #include <ctype.h>
  68. #include <errno.h>
  69. /*
  70. #include <string.h>
  71. */
  72. #include "cdialect.h"
  73. #include <sys/types.h>
  74.  
  75. /* returns a pointer in the buffer of the first free byte.
  76.    if it overflows, then NULL is returned 
  77.  */
  78. char *
  79. generate_search_apdu(buff,
  80.              buff_len,
  81.              seed_words,
  82.              database_name,
  83.              docobjs,
  84.              maxDocsRetrieved)
  85. char* buff;     /* buffer to hold the apdu */
  86. long *buff_len;    /* length of the buffer changed to reflect new data written */
  87. char *seed_words;    /* string of the seed words */
  88. char *database_name;
  89. DocObj** docobjs;
  90. long maxDocsRetrieved;
  91. {
  92.   /* local variables */
  93.  
  94.   SearchAPDU *search3;
  95.   char  *end_ptr;
  96.   static char *database_names[2] = {"", 0};
  97.   any refID;
  98.   WAISSearch *query;
  99.   refID.size = 1;
  100.   refID.bytes = "3";
  101.  
  102.   database_names[0] = database_name;
  103.   query = makeWAISSearch(seed_words,
  104.                          docobjs, /* DocObjsPtr */
  105.                          0L,
  106.                          1L,     /* DateFactor */
  107.                          0L,     /* BeginDateRange */
  108.                          0L,     /* EndDateRange */
  109.                          maxDocsRetrieved
  110.                          );
  111.  
  112.   search3 = makeSearchAPDU(30L, 
  113.                5000L, /* should be large */
  114.                30L,
  115.                            1L,    /* replace indicator */
  116.                            "",    /* result set name */
  117.                            database_names, /* database name */   
  118.                            QT_RelevanceFeedbackQuery, /* query_type */
  119.                            0L,   /* element name */
  120.                            NULL, /* reference ID */
  121.                            query);
  122.  
  123.   end_ptr = writeSearchAPDU(search3, buff, buff_len);
  124.  
  125.   CSTFreeWAISSearch(query);
  126.   freeSearchAPDU(search3);
  127.   return(end_ptr);
  128. }
  129.  
  130.  
  131. /* returns a pointer into the buffer of the next free byte.
  132.    if it overflowed, then NULL is returned
  133.  */
  134.  
  135. char *
  136.  generate_retrieval_apdu(buff,
  137.             buff_len,
  138.             docID,
  139.             chunk_type,
  140.             start,
  141.             end,
  142.             type,
  143.             database_name)
  144. char *buff;
  145. long *buff_len;    /* length of the buffer changed to reflect new data written */
  146. any *docID;
  147. long chunk_type;
  148. long start;
  149. long end;
  150. char *type;
  151. char *database_name;
  152. {
  153.   SearchAPDU *search;
  154.   char  *end_ptr;
  155.  
  156.   static char *database_names[2];
  157.   static char *element_names[3];
  158.   any refID;
  159.  
  160.   DocObj *DocObjs[2];
  161.   any *query;            /* changed from char* by brewster */
  162.  
  163.   if(NULL == type)
  164.     type = s_strdup("TEXT");
  165.  
  166.   database_names[0] = database_name;
  167.   database_names[1] = NULL;
  168.  
  169.   element_names[0] = " ";
  170.   element_names[1] = ES_DocumentText;
  171.   element_names[2] = NULL;
  172.  
  173.   refID.size = 1;
  174.   refID.bytes = "3";
  175.   
  176.   switch(chunk_type){
  177.   case CT_line: 
  178.     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  179.     break;
  180.   case CT_byte:
  181.     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  182.     break;
  183.   }
  184.   DocObjs[1] = NULL;
  185.  
  186.   query = makeWAISTextQuery(DocObjs);   
  187.   search = makeSearchAPDU( 10L, 16L, 15L, 
  188.               1L,    /* replace indicator */
  189.               "FOO", /* result set name */
  190.               database_names, /* database name */   
  191.               QT_TextRetrievalQuery, /* query_type */
  192.               element_names, /* element name */
  193.               &refID, /* reference ID */
  194.               query);
  195.   end_ptr = writeSearchAPDU(search, buff, buff_len);
  196.   /* s_free(DocObjs[0]->Type); it's a copy of the input, don't free it! */
  197.   CSTFreeDocObj(DocObjs[0]);
  198.   CSTFreeWAISTextQuery(query);
  199.   freeSearchAPDU(search);
  200.   return(end_ptr);
  201. }
  202.  
  203. /* not currently used 
  204.  
  205. static boolean isnumber _AP((char* string));
  206.  
  207. static boolean isnumber(string)
  208. char *string;
  209. {
  210.   long count;
  211.   for(count = 0; count < strlen(string); count++){
  212.     if(!isdigit(string[count])){
  213.       return(false);
  214.     }
  215.   }
  216.   return(true);
  217. }
  218.  
  219. */
  220.  
  221. /* this will negotiate with server, and returs the maximum buffer size 
  222.    the server can handle.
  223.  
  224.    A connection should be established first using open_socket.
  225.  
  226. */
  227.  
  228. long init_connection(inBuffer, outBuffer, bufferSize, connection, userInfo)
  229. char *inBuffer, *outBuffer;
  230. long bufferSize;
  231. FILE *connection;
  232. char *userInfo;
  233.   InitAPDU* init = NULL;
  234.   InitResponseAPDU* reply = NULL;
  235.   long result;
  236.   /* construct an init */
  237.   init = makeInitAPDU(true,false,false,false,false,bufferSize,bufferSize,
  238.               userInfo,defaultImplementationID(),
  239.               defaultImplementationName(),
  240.               defaultImplementationVersion(),NULL,userInfo);
  241.   /* write it to the buffer */
  242.   result = writeInitAPDU(init,inBuffer+HEADER_LENGTH,&bufferSize) - inBuffer;
  243.  
  244.   freeInitAPDU(init);           /* Free also if there is no error(up) */
  245.   if(result < 0){
  246.     return(-1);
  247.   }
  248.   if(0 ==
  249.      interpret_message(inBuffer,
  250.                result - HEADER_LENGTH,
  251.                outBuffer,
  252.                bufferSize,
  253.                connection,
  254.                false    /* true verbose */    
  255.                )) {
  256.     /* error making a connection */
  257.     return (-1);
  258.   }
  259.   if (readInitResponseAPDU(&reply,outBuffer + HEADER_LENGTH) == NULL){
  260.     freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  261.     freeInitResponseAPDU(reply);
  262.     return(-1);
  263.   }
  264.   if (reply->Result == false)
  265.     {                /* the server declined service */
  266.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  267.       freeInitResponseAPDU(reply);
  268.       return(-1);
  269.     }
  270.   else                /* we got a response back */
  271.     { result = reply->MaximumRecordSize;
  272.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  273.       freeInitResponseAPDU(reply);
  274.       return(result);
  275.     }
  276. }
  277.  
  278. #ifdef LOCAL_SEARCH
  279. /* returns the length of the response, 0 if an error */
  280. long
  281. locally_answer_message(request_message,
  282.                request_length,
  283.                response_message,
  284.                response_buffer_length)
  285. char *request_message;
  286. long request_length;
  287. char *response_message;
  288. long response_buffer_length;
  289. {
  290.   long request_length_internal = request_length;
  291.   long response_length;
  292.   WAISMessage header;
  293.   long maxBufferSize = response_buffer_length;
  294.  
  295.   readWAISPacketHeader(request_message, &header);
  296.   {
  297.     char length_array[11];
  298.     strncpy(length_array, header.msg_len, 10);
  299.     length_array[10] = '\0';
  300.     request_length_internal = atol(length_array);
  301.   }
  302.   /*
  303.     printf("request length is %ld (%ld from caller)\n", 
  304.     request_length_internal,
  305.     request_length);
  306.     */
  307.   
  308.   response_length =
  309.     interpret_buffer(request_message + HEADER_LENGTH, 
  310.              request_length_internal,
  311.              response_message + HEADER_LENGTH,
  312.              response_buffer_length,
  313.              &maxBufferSize,
  314.              (long)header.hdr_vers,
  315.              "");
  316.   if(0 > response_length)
  317.     return(0);
  318.   writeWAISPacketHeader(response_message,
  319.             response_length,
  320.             (long)'z',    /* Z39.50 */
  321.             "DowQuest  ", /* server name */
  322.             (long)NO_COMPRESSION,    /* no compression */
  323.             (long)NO_ENCODING,(long)header.hdr_vers);
  324.   return(response_length);
  325. }
  326. #endif
  327.  
  328. /* this is a safe version of unix 'read' it does all the checking
  329.  * and looping necessary
  330.  * to those trying to modify the transport code to use non-UNIX streams:
  331.  *  This is the function to modify!
  332.  */
  333. long read_from_stream(d,buf,nbytes)
  334. long d;                /* this is the stream */
  335. char *buf;
  336. long nbytes;
  337. {
  338.   long didRead;
  339.   long toRead = nbytes;
  340.   long totalRead = 0;        /* paranoia */
  341.  
  342.   while (toRead > 0){
  343.     didRead = read (d, buf, toRead);
  344.     if(didRead == -1)        /* error*/
  345.       return(-1);
  346.     if(didRead == 0)        /* eof */
  347.       return(-2);        /* maybe this should return 0? */
  348.     toRead -= didRead;
  349.     buf += didRead;
  350.     totalRead += didRead;
  351.   }
  352.   if(totalRead != nbytes)    /* we overread for some reason */
  353.     return(- totalRead);    /* bad news */    
  354.   return(totalRead);
  355. }
  356.  
  357. /* returns the length of the response, 0 if an error */
  358.  
  359. long 
  360. transport_message(connection,
  361.           request_message,
  362.           request_length,
  363.           response_message,
  364.           response_buffer_length)
  365. FILE *connection;
  366. char *request_message;
  367. long request_length;
  368. char *response_message;
  369. long response_buffer_length;
  370. {
  371.   WAISMessage header;
  372.   long response_length;
  373.  
  374.   
  375.   /* Write out message. Read back header. Figure out response length. */
  376.   
  377.   if( request_length + HEADER_LENGTH
  378.      != fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
  379.     return 0;
  380.  
  381.   fflush(connection);
  382.  
  383.   /* read for the first '0' */
  384.  
  385.   while(1){
  386.     if(0 > read_from_stream(fileno(connection), response_message, 1))
  387.       return 0;
  388.     if('0' == response_message[0])
  389.       break;
  390.   }
  391.  
  392.   if(0 > read_from_stream(fileno(connection), 
  393.                   response_message + 1, 
  394.                   HEADER_LENGTH - 1))
  395.     return 0;
  396.  
  397.   readWAISPacketHeader(response_message, &header);
  398.   {
  399.     char length_array[11];
  400.     strncpy(length_array, header.msg_len, 10);
  401.     length_array[10] = '\0';
  402.     response_length = atol(length_array);
  403.     /*
  404.       if(verbose){
  405.       printf("WAIS header: '%s' length_array: '%s'\n", 
  406.       response_message, length_array);
  407.       }
  408.       */
  409.     if(response_length > response_buffer_length){
  410.       /* we got a message that is too long, therefore empty the message out,
  411.      and return 0 */
  412.       long i;
  413.       for(i = 0; i < response_length; i++){
  414.     read_from_stream(fileno(connection), 
  415.              response_message + HEADER_LENGTH,
  416.              1);
  417. /*    fread(response_message + HEADER_LENGTH, 1, 1, connection); */
  418.       }
  419.       return(0);
  420.     }
  421.   }
  422.   if(0 > read_from_stream(fileno(connection), 
  423.                   response_message + HEADER_LENGTH,
  424.                   response_length))
  425. /*  if(0 > fread(response_message + HEADER_LENGTH,
  426.            1, response_length, connection)) */
  427.     return 0;
  428.   return(response_length);
  429. }
  430.  
  431.  
  432. /* ------------------------------------------------------------*/
  433.  
  434. /*  Facility to record messages sent and recieved for testing 
  435.     and timing purposes. */
  436.  
  437. /* from c:
  438.  
  439.    putenv(strdup("IR_FILE=/users/menlo-park/brewster/tmp/infile"));
  440.  
  441.    from csh:
  442.  
  443.    setenv IR_FILE /users/menlo-park/brewster/tmp/infile
  444.  
  445.  */
  446.  
  447. boolean environment_variables_read = false; 
  448. char* ir_file_environment_variable = "IR_FILE";
  449. char* ir_file = NULL;
  450.  
  451. void read_environment_variables(host, port)
  452.      char* host;
  453.      char* port;
  454. {
  455.   
  456.   if(!environment_variables_read){
  457.     FILE *stream;
  458.     ir_file = (char*)getenv(ir_file_environment_variable);
  459.     if(ir_file){
  460.       printf("IR_file: %s\n", ir_file);
  461.       stream = fopen(ir_file, "w");
  462.       fprintf(stream, "%s %s\n", host, port);
  463.       fclose(stream);
  464.     }
  465.     environment_variables_read = true;
  466.   }
  467. }
  468.  
  469. /* returns 0 if success */
  470. long write_message_to_file(message, length, filename)
  471.      unsigned char *message;
  472.      long length;
  473.      char*filename;
  474. {
  475.   FILE *stream = fopen(filename, "a");
  476.   if(NULL == stream)
  477.     return(-1);
  478.   
  479.   printf("Writing to file: %s %d characters\n", filename, length);
  480.  
  481.   fprintf(stream, "---------------------------------\n");
  482.   
  483.   if(length != fwrite(message, sizeof(unsigned char), 
  484.               length, stream)){
  485.     perror("fwrite error");
  486.     fclose(stream);
  487.     return(-2);
  488.   }
  489.  
  490.   fprintf(stream, "\n");
  491.  
  492.   if(0 != fclose(stream))
  493.     return(-3);
  494.   return(0);
  495. }  
  496.  
  497. /* ------------------------------------------------------------*/
  498.  
  499. /* returns the number of bytes writeen.  0 if an error */
  500. long
  501. interpret_message(request_message,request_length,
  502.           response_message,
  503.           response_buffer_length,
  504.           connection,
  505.           verbose)
  506. char *request_message;
  507. long request_length; /* length of the buffer */
  508. char *response_message;
  509. long response_buffer_length;
  510. FILE *connection;
  511. boolean verbose;
  512. {
  513.   long response_length;
  514.  
  515.   writeWAISPacketHeader(request_message,
  516.             request_length,
  517.             (long)'z',    /* Z39.50 */
  518.             "wais      ", /* server name */
  519.             (long)NO_COMPRESSION,    /* no compression */
  520.             (long)NO_ENCODING,(long)HEADER_VERSION);
  521.  
  522.   if(ir_file){
  523.     long error_code;
  524.     if(0 != (error_code = 
  525.          write_message_to_file((unsigned char*)request_message, 
  526.                    request_length + HEADER_LENGTH, 
  527.                    ir_file)))
  528.       printf("Error writing log file Code: %d\n", error_code);
  529.   }
  530.     
  531.   if(connection != NULL) {
  532.     if(0 == 
  533.        (response_length =
  534.     transport_message(connection, request_message,
  535.               request_length,
  536.               response_message,
  537.               response_buffer_length)))
  538.       return(0);
  539.   }
  540.   else{
  541. #ifdef LOCAL_SEARCH    
  542.     if(0 == 
  543.        (response_length =
  544.     locally_answer_message(request_message, request_length, 
  545.                    response_message,
  546.                    response_buffer_length)))
  547.       return(0);
  548. #else
  549.     waislog(WLOG_HIGH, WLOG_ERROR, "Local search not supported in this version");
  550.     return(0);
  551. #endif
  552.   }
  553.   if(verbose){
  554.     printf ("decoded %ld bytes: \n", response_length);
  555.     twais_dsply_rsp_apdu(response_message + HEADER_LENGTH, 
  556.              request_length);
  557.   }
  558.   if(ir_file){
  559.     long error_code;
  560.     if(0 != (error_code = 
  561.          write_message_to_file((unsigned char*)response_message, 
  562.                    response_length + HEADER_LENGTH, 
  563.                    ir_file)))
  564.       printf("Error writing log file Code: %d\n", error_code);
  565.   }
  566.   return(response_length);
  567. }
  568.  
  569. /* this closes the connection to the socket.
  570.  * the mythology is that this is cleaner than exiting
  571.  */
  572.  
  573. long close_connection(connection)
  574. FILE *connection;
  575. {
  576.   long result = 0;
  577.   
  578.   if(connection != NULL){
  579.     result = fclose(connection);
  580.   }
  581.   return(result);
  582. }
  583.   
  584. void
  585. display_text_record_completely(record,quote_string_quotes)
  586. WAISDocumentText *record;
  587. boolean quote_string_quotes;
  588. {
  589.   long count;
  590.   /* printf(" Text\n");
  591.      print_any("     DocumentID:  ", record->DocumentID);
  592.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  593.      */
  594.   for(count = 0; count < record->DocumentText->size; count++){
  595.     long ch = (unsigned char)record->DocumentText->bytes[count];
  596.     if(27 == ch){
  597.       /* then we have an escape code */
  598.       /* if the next letter is '(' or ')', then ignore two letters */
  599.       if('(' == record->DocumentText->bytes[count + 1] ||
  600.      ')' == record->DocumentText->bytes[count + 1])
  601.     count += 1;             /* it is a term marker */
  602.       else count += 4;        /* it is a paragraph marker */
  603.     }
  604.     else if (ch == '\t') /* a TAB! */
  605.       putc(ch, stdout);
  606.     else if (isprint(ch)){
  607.       if(quote_string_quotes && ch == '"')
  608.     putc('\\', stdout);
  609.       putc(ch, stdout);
  610.     } 
  611.     else if (ch == '\n' || ch == '\r')
  612.       printf ("\n");
  613.   }
  614. }
  615.  
  616. /* modifies the string to exclude all seeker codes. sets length to
  617.    the new length. */
  618. char *delete_seeker_codes(string,length)
  619. char *string;
  620. long *length;
  621. {
  622.   long original_count; /* index into the original string */
  623.   long new_count = 0; /* index into the collapsed string */
  624.   for(original_count = 0; original_count < *length; original_count++){
  625.     if(27 == string[original_count]){
  626.       /* then we have an escape code */
  627.       /* if the next letter is '(' or ')', then ignore two letters */
  628.       if('(' == string[original_count + 1] ||
  629.     ')' == string[original_count + 1])
  630.      original_count += 1;    /* it is a term marker */
  631.       else original_count += 4; /* it is a paragraph marker */
  632.     }
  633.     else string[new_count++] = string[original_count];
  634.   }
  635.   *length = new_count;
  636.   return(string);
  637. }
  638.  
  639.  
  640.   
  641. /* returns a pointer to a string with good stuff */
  642. char *trim_junk(headline)
  643. char *headline;
  644. {
  645.   long length = strlen(headline) + 1; /* include the trailing null */
  646.   long i,j;
  647.   headline = delete_seeker_codes(headline, &length);
  648.  
  649.  
  650.   /* delete leading spaces */
  651.   for(i=0; i < strlen(headline); i++){
  652.     if(isprint(headline[i])){
  653.       break;
  654.     }
  655.   }
  656.   headline = headline + i;
  657.   /* delete trailing stuff */
  658.   for (i = 0, j = 0; i < strlen(headline)+1; i++) {
  659.     if ((headline[i] != '\r') && (headline[i] != '\n')) {
  660.       headline[j++] = headline[i];
  661.     }
  662.   }
  663.   
  664.  
  665.   for(i=strlen(headline) - 1 ; i > 0; i--){
  666.     if(isprint(headline[i])){
  667.       break;
  668.     }
  669.     headline[i] = '\0';
  670.   }
  671.   
  672.   return(headline);
  673. }
  674.  
  675.  
  676.  
  677.